﻿// http://gallery.expression.microsoft.com/ScrollVMouseOffsetBH

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;

namespace CPN.PJN.Silverlight.UI.Interactions.Behaviors
{
    public class ScrollBarMouseOffsetBehavior : Behavior<ScrollViewer>
    {
        public double ScrollingPercentage
        {
            get { return (double)GetValue(ScrollingPercentageProperty); }
            set {

                if (value >= 0 && value <= 1)
                {
                    SetValue(ScrollingPercentageProperty, value);
                }
                else
                {
                    throw new Exception("ScrollingPercentage must be a percentage number (>=0 and <=1)");
                }
            }
        }

        public static readonly DependencyProperty ScrollingPercentageProperty =
            DependencyProperty.Register("ScrollingPercentage", typeof(double), typeof(ScrollBarMouseOffsetBehavior), new PropertyMetadata(0.25d));


        public double ScrollingVelocity
        {
            get { return (double)GetValue(ScrollingVelocityProperty); }
            set { SetValue(ScrollingVelocityProperty, value); }
        }

        public static readonly DependencyProperty ScrollingVelocityProperty =
            DependencyProperty.Register("ScrollingVelocity", typeof(double), typeof(ScrollBarMouseOffsetBehavior), new PropertyMetadata(0.01d) );



        public Orientation Orientation
        {
            get { return (Orientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        public static readonly DependencyProperty OrientationProperty =
            DependencyProperty.Register("Orientation", typeof(Orientation), typeof(ScrollBarMouseOffsetBehavior), new PropertyMetadata(Orientation.Horizontal));

        
        private double ownerWidth = 0;
        private double ownerHeight = 0;

        bool rendering = false;
        double sensor = 0;

        public ScrollBarMouseOffsetBehavior()
        {
        }

        protected override void OnAttached()
        {
            base.OnAttached();

            this.AssociatedObject.MouseEnter += AssociatedObject_MouseEnter;
            this.AssociatedObject.MouseMove += AssociatedObject_MouseMove;
            this.AssociatedObject.MouseLeave += ((sender, e)=> rendering = false);

            CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
        }

        void AssociatedObject_MouseMove(object sender, MouseEventArgs e)
        {
            ScrollViewer el = sender as ScrollViewer;
           
            Point mousePoint = e.GetPosition(el);

            if (Orientation == Orientation.Horizontal)
            {
                ownerWidth = this.AssociatedObject.ActualWidth;

                double middleX = this.AssociatedObject.ActualWidth / 2;

                double percent = 0;

                if (mousePoint.X > 0 && mousePoint.X <= ownerWidth * ScrollingPercentage)
                {
                    rendering = true;
                    percent = Math.Abs(mousePoint.X - middleX) * 100;
                    sensor = percent / 100 * ScrollingVelocity;
                }

                else if (mousePoint.X <= ownerWidth && mousePoint.X >= ownerWidth * (1 - ScrollingPercentage))
                {
                    rendering = true;
                    percent = -Math.Abs(mousePoint.X - middleX) * 100;
                    sensor = percent / 100 * ScrollingVelocity;
                }
                else
                {
                    rendering = false;
                }
            }
            else
            {
                ownerHeight = this.AssociatedObject.ActualHeight;

                double middleY = this.AssociatedObject.ActualHeight / 2;

                double percent = 0;

                if (mousePoint.Y > 0 && mousePoint.Y <= ownerHeight * ScrollingPercentage)
                {
                    rendering = true;
                    percent = Math.Abs(mousePoint.Y - middleY) * 100;
                    sensor = percent / 100 * ScrollingVelocity;
                }

                else if (mousePoint.Y <= ownerHeight && mousePoint.Y >= ownerHeight * (1 - ScrollingPercentage))
                {
                    rendering = true;
                    percent = -Math.Abs(mousePoint.Y - middleY) * 100;
                    sensor = percent / 100 * ScrollingVelocity;
                }
                else
                {
                    rendering = false;
                }
            }
        }

        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            if (rendering)
            {
                if (Orientation == Orientation.Horizontal)
                {
                    this.AssociatedObject.ScrollToHorizontalOffset(this.AssociatedObject.HorizontalOffset - sensor);
                }
                else
                {
                    this.AssociatedObject.ScrollToVerticalOffset(this.AssociatedObject.VerticalOffset - sensor);
                }
            }
        }

        void AssociatedObject_MouseEnter(object sender, MouseEventArgs e)
        {
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            
            this.AssociatedObject.MouseEnter -= AssociatedObject_MouseEnter;
            this.AssociatedObject.MouseMove -= AssociatedObject_MouseMove;
            this.AssociatedObject.MouseLeave -= ((sender, e) => rendering = false);
        }

       
    }
}